﻿using System;
using System.IO;
using System.Net.Sockets;

namespace Pfz.Remoting
{
	/// <summary>
	/// Channeller for tcp/ip connections.
	/// </summary>
	public sealed class ChannellerConnection:
		StreamChanneller
	{
		private IConnection _connection;
		private ChannellerConnection(IConnection connection, Stream stream, int bufferSizePerChannel):
			base(stream, bufferSizePerChannel, connection.LocalEndpoint, connection.RemoteEndpoint)
		{
			_connection = connection;
		}

		/// <summary>
		/// Creates a new channeller over the given tcp/ip client.
		/// </summary>
		public static ChannellerConnection Create(TcpClient client, int bufferSizePerChannel, CryptographySide cryptographySide=CryptographySide.None)
		{
			if (client == null)
				throw new ArgumentNullException("client");

			client.NoDelay = true;
			client.ReceiveBufferSize = bufferSizePerChannel;
			client.SendBufferSize = 0;
			return Create(new DisposableTcpConnection(client), bufferSizePerChannel, cryptographySide);
		}

		/// <summary>
		/// Creates a new channeller connection over an existing connection.
		/// </summary>
		public static ChannellerConnection Create(IConnection connection, int bufferSizePerChannel, CryptographySide cryptographySide=CryptographySide.None)
		{
			if (connection == null)
				throw new ArgumentNullException("connection");

			Stream stream = connection.Stream;
			switch(cryptographySide)
			{
				case CryptographySide.None:
					break;

				case CryptographySide.Client:
					stream = new SecureStream(stream, false);
					break;

				case CryptographySide.Server:
					stream = new SecureStream(stream, true);
					break;

				default:
					throw new ArgumentException("cryptographySide has an unknown value.");
			}

			return new ChannellerConnection(connection, stream, bufferSizePerChannel);
		}

		/// <summary>
		/// Releases all resources.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
				Disposer.Dispose(ref _connection);

			base.Dispose(disposing);
		}
	}
}
